package com.zhentao.service.impl;

import com.zhentao.service.WeChatService;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Service
public class WeChatServiceImpl implements WeChatService {
    private static final Logger log = LoggerFactory.getLogger(WeChatServiceImpl.class);

    @Value("${wechat.mock.enabled:false}")
    private boolean mockEnabled;

    @Value("${wechat.appid:}")
    private String appId;

    @Value("${wechat.secret:}")
    private String secret;

    @Value("${wechat.api.jscode2session:https://api.weixin.qq.com/sns/jscode2session}")
    private String jscode2sessionUrl;

    @Value("${wechat.api.token:https://api.weixin.qq.com/cgi-bin/token}")
    private String tokenUrl;

    @Value("${wechat.api.getphone:https://api.weixin.qq.com/wxa/business/getuserphonenumber}")
    private String getPhoneUrl;

    @Override
    public Map<String, Object> code2Session(String code) {
        Map<String, Object> result = new HashMap<>();
        if (code == null || code.trim().isEmpty()) {
            result.put("errcode", 400);
            result.put("errmsg", "code 不能为空");
            return result;
        }
        // 开发环境 Mock：无需真实 appid/secret 与外网请求
        if (mockEnabled) {
            Map<String, Object> mock = new HashMap<>();
            mock.put("errcode", 0);
            mock.put("openid", "mock_openid_" + code.trim());
            mock.put("session_key", "mock_session_key_" + code.trim());
            mock.put("unionid", null);
            return mock;
        }
        if (appId == null || appId.isEmpty() || secret == null || secret.isEmpty()) {
            result.put("errcode", 500);
            result.put("errmsg", "未配置 wechat.appid/secret");
            return result;
        }
        String url = String.format("%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                jscode2sessionUrl, appId, secret, code);
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpGet get = new HttpGet(url);
            try (CloseableHttpResponse resp = client.execute(get)) {
                String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
                if (body == null || body.isEmpty()) {
                    Map<String, Object> err = new HashMap<>();
                    err.put("errcode", 500);
                    err.put("errmsg", "微信返回空响应");
                    return err;
                }
                ObjectMapper mapper = new ObjectMapper();
                Map<String, Object> parsed = mapper.readValue(body, new TypeReference<Map<String, Object>>(){});
                return parsed != null ? parsed : new HashMap<>();
            }
        } catch (Exception e) {
            log.error("调用 jscode2session 失败", e);
            Map<String, Object> err = new HashMap<>();
            err.put("errcode", 500);
            err.put("errmsg", "调用 jscode2session 异常:" + e.getMessage());
            return err;
        }
    }

    @Override
    public String decryptPhone(String sessionKey, String iv, String encryptedData) {
        // 为避免引入复杂依赖，这里暂返回 null。
        // 如果前端走 getPhoneNumber 新版接口，建议将手机号直接传至后端，无需解密。
        return null;
    }

    @Override
    public String getAccessToken() {
        // 开发环境 Mock：直接返回固定 token
        if (mockEnabled) {
            return "mock_access_token";
        }
        if (appId == null || appId.isEmpty() || secret == null || secret.isEmpty()) {
            return null;
        }
        String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s", tokenUrl, appId, secret);
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpGet get = new HttpGet(url);
            try (CloseableHttpResponse resp = client.execute(get)) {
                String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
                if (body == null || body.isEmpty()) return null;
                ObjectMapper mapper = new ObjectMapper();
                Map<String, Object> parsed = mapper.readValue(body, new TypeReference<Map<String, Object>>(){});
                Object token = parsed.get("access_token");
                return token != null ? String.valueOf(token) : null;
            }
        } catch (Exception e) {
            log.error("获取 access_token 失败", e);
            return null;
        }
    }

    @Override
    public String getUserPhoneByCode(String code) {
        // 开发环境 Mock：返回演示手机号
        if (mockEnabled) {
            return "13800138000";
        }
        if (code == null || code.trim().isEmpty()) return null;
        String accessToken = getAccessToken();
        if (accessToken == null) return null;
        String url = String.format("%s?access_token=%s", getPhoneUrl, accessToken);
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            // 微信该接口要求 POST JSON：{"code":"xxx"}
            org.apache.http.client.methods.HttpPost post = new org.apache.http.client.methods.HttpPost(url);
            post.setHeader("Content-Type", "application/json;charset=UTF-8");
            String payload = "{\"code\":\"" + code + "\"}";
            post.setEntity(new org.apache.http.entity.StringEntity(payload, StandardCharsets.UTF_8));
            try (CloseableHttpResponse resp = client.execute(post)) {
                String body = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
                if (body == null || body.isEmpty()) return null;
                ObjectMapper mapper = new ObjectMapper();
                Map<String, Object> parsed = mapper.readValue(body, new TypeReference<Map<String, Object>>(){});
                // 期望结构：{"code":0,"data":{"phoneNumber":"xxxx","purePhoneNumber":"xxxx"}}
                Object codeField = parsed.get("code");
                if (codeField instanceof Number && ((Number) codeField).intValue() == 0) {
                    Object data = parsed.get("data");
                    if (data instanceof Map) {
                        Object phone = ((Map) data).get("phoneNumber");
                        if (phone == null) phone = ((Map) data).get("purePhoneNumber");
                        return phone != null ? String.valueOf(phone) : null;
                    }
                }
            }
        } catch (Exception e) {
            log.error("通过 code 获取手机号失败", e);
        }
        return null;
    }

}